package com.xx.job.filter;


import com.alibaba.fastjson.JSONObject;

import com.xx.job.common.util.OsAndBrowserInfoUtil;
import com.xx.job.entity.system.SysConfig;
import com.xx.job.entity.system.SysLoginLog;
import com.xx.job.entity.system.SysOperaLog;
import com.xx.job.entity.system.SysUser;
import com.xx.job.service.system.SysConfigService;
import com.xx.job.service.system.SysLoginLogService;
import com.xx.job.service.system.SysOperaLogService;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @Author shengjie
 * @create 2019/12/6 10:32
 */
@Slf4j
public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered {

    @Autowired
    private SysOperaLogService sysOperaLogService;
    @Autowired
    private SysLoginLogService sysLoginLogService;


    /**
     * 统一拦截的接口路径配置
     */
    private static final String NEED_TRACE_PATH_PREFIX_LOGIN = "/login";

    private static final String NEED_TRACE_PATH_PREFIX = "/api";
    /**
     * 拦截类型
     */
    private static final String IGNORE_CONTENT_TYPE = "multipart/form-data";

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }

   /* private final MeterRegistry registry;

    public HttpTraceLogFilter(MeterRegistry registry) {
        this.registry = registry;
    }*/

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        if (!isRequestValid(request)) {
            filterChain.doFilter(request, response);
            return;
        }
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        long startTime = System.currentTimeMillis();
        try {
            filterChain.doFilter(request, response);
            status = response.getStatus();
        } finally {
            //请求路径
            // 登录人
            SysUser sysUser = (SysUser)request.getSession().getAttribute("sysUser");
            String path = request.getRequestURI();
            StringBuffer requestURL = request.getRequestURL();
            String method = request.getMethod();
            OsAndBrowserInfoUtil osAndBrowserInfoUtil = new OsAndBrowserInfoUtil(request);
            // 浏览器
            String browser = osAndBrowserInfoUtil.getBrowser();
            // 系统
            String os = osAndBrowserInfoUtil.getOs();
            OsAndBrowserInfoUtil.getOsAndBrowserInfo(request);
            if (path.startsWith(NEED_TRACE_PATH_PREFIX) && !Objects.equals(IGNORE_CONTENT_TYPE, request.getContentType())) {
                // 访问日志
                SysOperaLog sysOperaLog = new SysOperaLog();
                sysOperaLog.setCreatedAt(LocalDateTime.now());
                sysOperaLog.setUpdatedAt(LocalDateTime.now());
                sysOperaLog.setRequestMethod(method);
                if(sysUser != null){
                    sysOperaLog.setOperName(sysUser.getUsername());
                }
                sysOperaLog.setOperUrl(requestURL+"");
                sysOperaLog.setOperIp(path);
                //请求参数
                String requestBody = getRequestBody(request);
                if (StringUtils.isNotBlank(requestBody)) {
                    sysOperaLog.setOperParam(requestBody.replaceAll("\\s ", ""));
                } else {
                    sysOperaLog.setOperParam("");
                }
                long timeConsuming = System.currentTimeMillis() - startTime;
                sysOperaLog.setLatencyTime(timeConsuming+"");
                sysOperaLog.setStatus(status+"");
                //响应参数
                String responseBody = getResponseBody(response);
                sysOperaLog.setJsonResult(requestBody);
                sysOperaLogService.add(sysOperaLog);


            } else if(path.startsWith(NEED_TRACE_PATH_PREFIX_LOGIN) && !Objects.equals(IGNORE_CONTENT_TYPE, request.getContentType())){
                // 登录日志
                SysLoginLog sysLoginLog = new SysLoginLog();

                if(sysUser != null){
                    sysLoginLog.setUsername(sysUser.getUsername());
                }
                // ip地址
                sysLoginLog.setIpaddr(path);
                // 归属地 TODO
                sysLoginLog.setLoginLocation("内部ip");
                // 浏览器
                sysLoginLog.setBrowser(browser);
                // 系统
                sysLoginLog.setOs(os);
                // 登录时间
                sysLoginLog.setLoginTime(LocalDateTime.now());
                sysLoginLogService.add(sysLoginLog);
            }
            updateResponse(response);
        }
    }

    private boolean isRequestValid(HttpServletRequest request) {
        try {
            new URI(request.getRequestURL().toString());
            return true;
        } catch (URISyntaxException ex) {
            return false;
        }
    }

    private String getRequestBody(HttpServletRequest request) {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            try {
                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
                return "";
            }
        }
        return requestBody;
    }

    private String getResponseBody(HttpServletResponse response) {
        String responseBody = "";
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            try {
                responseBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
                return responseBody;
            }
        }
        return responseBody;
    }

    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        Objects.requireNonNull(responseWrapper).copyBodyToResponse();
    }

}
